package org.tagging.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.quartz.*;
import org.quartz.impl.JobDetailImpl;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.tagging.exception.UnSupportedConditionException;
import org.tagging.exception.UnSupportedLanguageException;
import org.tagging.model.Abbreviation;
import org.tagging.model.Tag;
import org.tagging.model.Tagging;
import org.tagging.model.UnknownWord;
import org.tagging.service.AbbreviationService;
import org.tagging.service.TaggingService;
import org.tagging.service.UnknownWordService;
import org.tagging.service.factory.TaggingServiceFactory;
import org.tagging.service.impl.other.ClientUserServiceImpl;
import org.tagging.utils.ResponseUtils;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

@RestController
@RequestMapping("/api/tagging")
@Api(value = "标注系统", tags = "标注相关接口")
public class TaggingController implements InitializingBean, DisposableBean {
    private static final Logger logger = LoggerFactory.getLogger(TaggingController.class);

    @Value("${tagging.clear.time:7200000}")
    private Long scheduledTime;

    @Autowired(required = false)
    private SimpleTriggerImpl trigger;

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private TaggingServiceFactory taggingServiceFactory;

    @Autowired
    private ClientUserServiceImpl userService;

    @Override
    public void afterPropertiesSet() throws Exception {
        logger.info("注册定时清理每天标注数据量成功！");
        JobDetailImpl jobDetail = new JobDetailImpl();
        jobDetail.setKey(new JobKey("clearing", "Tagging"));
        jobDetail.setJobClass(ClearClass.class);
        JobDataMap dataMap = new JobDataMap();
        dataMap.put("userService", userService);
        jobDetail.setJobDataMap(dataMap);
        CronTriggerImpl cronTrigger = new CronTriggerImpl();
        cronTrigger.setName("clearingCompleteToday");
        cronTrigger.setCronExpression("59 59 23 * * ?");
//        cronTrigger.setCronExpression("55 * 16 * * ?");
        scheduler.scheduleJob(jobDetail, cronTrigger);
    }

    private class ClearClass implements Job {
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            logger.info("开始清理用户今日标注的数据量");
            ClientUserServiceImpl userService = (ClientUserServiceImpl) context.getMergedJobDataMap().get("userService");
            userService.clearCompleteToday();
            logger.info("清理用户今日标注的数据量成功");
        }
    }

    @Override
    public void destroy() throws Exception {
        //此处本想做些回调方法，TODO
//        IndonesianServiceImpl indonesianService = (IndonesianServiceImpl) taggingServiceFactory.getTaggingService("indonesian");
//        MalayServiceImpl malayService = (MalayServiceImpl) taggingServiceFactory.getTaggingService("malay");
//        List<TaggingUser> taggingUsers = userService.queryIds();
//        for (TaggingUser taggingUser : taggingUsers) {
//            indonesianService.clearUsingBy();
//        }
    }

    private class ClearingUsingByJob implements org.quartz.Job {
        @Override
        @SuppressWarnings("unchecked")
        public void execute(JobExecutionContext context) {
            List<Integer> tagIds = (List<Integer>) context.getMergedJobDataMap().get("tagIds");
            TaggingService taggingService = (TaggingService) context.getMergedJobDataMap().get("taggingService");
            for (Integer tagId : tagIds) {
                taggingService.clearUsingBy(tagId);
            }
        }
    }

    @GetMapping("/list")
    @PreAuthorize("hasAnyRole('USER') or hasAnyAuthority('tagging_list')")
    @ApiOperation(value = "获取待标注的数据", notes = "所需权限(tagging_list)size:数据量大小;language:malay或indonesian或philippines;\r\ncondition:default(集成标注) | notTranslate(未被翻译过) | notAbbreviate(未标注过缩略语) | notUnknownWord(未标注过未知词)")
    public String list(HttpServletResponse response, @ApiParam(value = "要多少条数据", example = "10") @RequestParam("size") Integer size,
                       @ApiParam(value = "language", example = "malay或indonesian") @RequestParam("language") String language,
                       @ApiParam(value = "condition", example = "default(集成标注) | notTranslate(未被翻译过) | notAbbreviate(未标注过缩略语) | notUnknownWord(未标注过未知词)") @RequestParam(value = "condition", required = false, defaultValue = "default") String condition) throws SchedulerException, UnSupportedLanguageException, UnSupportedConditionException {
        //依据language来看获取的为哪个bean
        TaggingService taggingService = taggingServiceFactory.getTaggingService(language);
        AbbreviationService abbreviationService = taggingServiceFactory.getAbbreviationService(language);
        UnknownWordService unknownWordService = taggingServiceFactory.getUnknownWordService(language);
        //获取size条标注的句子并更新usingBy为该用户
        List res = null;
        switch (condition) {
            case "default": {
                res = taggingService.list(size);
                break;
            }
            case "notTranslate": {
                res = taggingService.listNotTranslate(size);
                break;
            }
            case "notAbbreviate": {
                res = taggingService.listNotAbbreviate(size);
                break;
            }
            case "notUnknownWord": {
                res = taggingService.listNotUnknownWord(size);
                break;
            }
            default:
                throw new UnSupportedConditionException("condition not supported->" + condition);
        }
        List<Tag> tag = new ArrayList<>(res.size());
        for (Object t : res) {
            Tagging tagging = (Tagging) t;
            Tag aTag = new Tag();
            List abbreviations = abbreviationService.queryByTagId(tagging.getId());
            List unknownWords = unknownWordService.queryByTagId(tagging.getId());
            aTag.setTagging(tagging);
            aTag.setTaggingAbbreviationList(abbreviations);
            aTag.setTaggingUnknownWords(unknownWords);
            tag.add(aTag);
        }
        addScheduledJob(res, ClearingUsingByJob.class, taggingService);
        return ResponseUtils.build(HttpStatus.OK.value(), "获取标注列表成功！", tag);
    }

    //强转换为Tagging
    private void addScheduledJob(List<Tagging> res, Class<ClearingUsingByJob> clearingUsingByJobClass, TaggingService taggingService) throws SchedulerException {
        List<Integer> integers = new ArrayList<>(res.size());
        for (Tagging re : res) {
            integers.add(re.getId());
        }
        JobDetailImpl jobDetail = new JobDetailImpl();
        JobDataMap dataMap = new JobDataMap();
        dataMap.put("tagIds", integers);
        dataMap.put("taggingService", taggingService);
        jobDetail.setJobDataMap(dataMap);
        jobDetail.setKey(new JobKey(UUID.randomUUID().toString(), "tagging_list"));
        jobDetail.setJobClass(clearingUsingByJobClass);
        SimpleTriggerImpl trigger = new SimpleTriggerImpl();
        trigger.setName(UUID.randomUUID().toString() + "_trigger_clear_list");
        trigger.setRepeatCount(1);
        trigger.setRepeatInterval(1);
        trigger.setStartTime(new Date(System.currentTimeMillis() + scheduledTime));
        scheduler.scheduleJob(jobDetail, trigger);
    }


    /**
     * 此处接口应写成-> /translation
     * @param data
     * @return
     * @throws UnSupportedLanguageException
     */
    @PostMapping(value = "/translate")
    @PreAuthorize("hasAnyAuthority('translate_example')")
    @ApiOperation(value = "翻译", notes = "所需权限(translate_example)application/json->{'id':100,'translation':'中文翻译'}")
    public String translate(@ApiParam(example = "{'id':100,'translation':'中文翻译'}", value = "该则标注的id及其翻译") @RequestBody Map<String, String> data) throws UnSupportedLanguageException {
        String language = "indonesian";//由于之前和前端对接接口时忘记了，临时写着，下次前端再来接接口时接上
        Integer id = Integer.valueOf(data.get("id"));
        Assert.notNull(id, "tag id 不应为空！");
        String translation = data.get("translation");
        Assert.notNull(translation, "translation 不应为空！");
        TaggingService<? extends Tagging> taggingService = taggingServiceFactory.getTaggingService(language);
        taggingService.translate(id, translation);
        taggingService.updateUpdateByAndTranslated(id);
        userService.incrementComplete(language);
//        TaggingUser taggingUser = userService.retrieveCurrentUserId(userService.retrieveCurrentUser());
//        taggingIndonesianService.updateExampleChineseByManualById(id, translation, taggingUser.getId());
//        taggingIndonesianService.updateExampleChineseByManualById(id, translation, -777);
        return ResponseUtils.build(HttpStatus.OK.value(), "update translation success!");
    }

//
//    @PostMapping("/reviewAbbreviation")
//    @PreAuthorize("hasAnyAuthority('abbreviation')")
//    @ApiOperation(value = "修改多则缩略语", notes = "所需权限(abbreviation)" +
//            "id:缩略语唯一id\r\n" +
////            "abbreviationComplete:缩略语\r\n" +
//            "abbreviationCompleteManual:缩略语完整形式(人工)\r\n" +
//            "abbreviationCompleteChinese:缩略语完整形式中文翻译\r\n" +
//            "status:1->correct|0->incorrect\r\n" +
//            " [{\n" +
//            "  \"id\": 42311,\n" +
////            "  \"abbreviation\": \"LY\",\n" +
//            "  \"abbreviationCompleteManual\": \"Liyuan\",\n" +
//            "  \"abbreviationCompleteChinese\": \"李源\",\n" +
//            "\"status\":0" +
//            "},{" +
//            "\"id\":1234,\n" +
////            "\"abbreviation:\"LY2\",\n" +
//            "  \"abbreviationCompleteManual\": \"Liyuan2\",\n" +
//            "  \"abbreviationCompleteChinese\": \"李源2\",\n" +
//            "}]\r\n")
//    //若需要扩展请修改Abbreviation的参数
//    public String abbreviationReview(@RequestBody List<Abbreviation> abbreviations) throws UnSupportedLanguageException {
//        if (abbreviations.size() == 0) {
//            return ResponseUtils.build(HttpStatus.OK.value(), "abbreviations size = 0!");
//        }
//        String language = "indonesian";//原因同上
//        TaggingService taggingService = taggingServiceFactory.getTaggingService(language);
//        AbbreviationService<? extends Abbreviation> abbreviationService = taggingServiceFactory.getAbbreviationService(language);
//        Abbreviation a = abbreviationService.queryById(abbreviations.get(0).getId());
//        taggingService.updateUpdateByAndAbbreviation(a.getTagId());
//        for (Abbreviation abbreviation : abbreviations) {
//            abbreviationService.update(abbreviation);
//        }
//        userService.incrementComplete(language);
//        return ResponseUtils.build(HttpStatus.OK.value(), "update abbreviations success!");
//    }


    /**
     * REST-> POST /abbreviation(添加)
     *      -> PUT /abbreviation（修改）
     * @param abbreviations
     * @return
     * @throws UnSupportedLanguageException
     */
    @PostMapping(path = {"/addAbbreviations","/reviewAbbreviation"})
    @PreAuthorize("hasAnyAuthority('abbreviation')")
    @ApiOperation(value = "添加印尼语多则缩略语", notes = "所需权限(abbreviation)" +
            "tagId:父类标签的id\r\n" +
            "abbreviation:缩略语" +
            "abbreviationCompleteManual:缩略语完整形式" +
            "abbreviationCompleteChinese:缩略语完整形式中文翻译" +
            "[\n" +
            "  {\n" +
            "    \"tagId\": 1,\n" +
            "    \"abbreviation\": \"LY3\",\n" +
            "    \"abbreviationComplete\": \"Liyuan\",\n" +
            "    \"abbreviationCompleteChinese\": \"李源3\"\n" +
            "  },\n" +
            "  {\n" +
            "    \"tagId\": 1,\n" +
            "    \"abbreviation\": \"LY3\",\n" +
            "    \"abbreviationComplete\": \"Liyuan\",\n" +
            "    \"abbreviationCompleteManual\": \"Liyuan3\",\n" +
            "    \"abbreviationCompleteChinese\": \"李源3\"\n" +
            "  },\n" +
            "  {\n" +
            "    \"tagId\": 1,\n" +
            "    \"abbreviation\": \"LY3\",\n" +
            "    \"abbreviationComplete\": \"Liyuan\",\n" +
            "    \"abbreviationCompleteManual\": \"Liyuan3\",\n" +
            "    \"abbreviationCompleteChinese\": \"李源3\"\n" +
            "  }\n" +
            "]")
    public String abbreviationBatchAdd(@RequestBody List<Abbreviation> abbreviations) throws UnSupportedLanguageException {
        String language = "indonesian";
        AbbreviationService<? extends Abbreviation> abbreviationService = taggingServiceFactory.getAbbreviationService(language);
        if (abbreviations.size() > 0) {
            TaggingService taggingService = taggingServiceFactory.getTaggingService(language);
            Integer tagId = abbreviations.get(0).getTagId();
            taggingService.updateUpdateByAndAbbreviation(tagId);
        }

        for (Abbreviation abbreviation : abbreviations) {
            if (abbreviation.getId() != null && abbreviation.getId() != -1) {
                abbreviationService.update(abbreviation);
            } else {
                abbreviationService.add(abbreviation);
            }
        }
        userService.incrementComplete(language);
        return ResponseUtils.build(HttpStatus.OK.value(), "add abbreviations success!");
    }


    /**
     * POST unknown-word(添加)
     * PUT  unknown-word(修改)
     * @param unknownWords
     * @param language
     * @return
     * @throws UnSupportedLanguageException
     */
    @ApiOperation(value = "添加多则未知词", notes = "所需权限(unknown_words)" +
            "restful的形式->language=>malay/indonesian/philippines\r\n" +
            "tagId:父类id\r\n" +
            "unknownWord:未知词\r\n" +
            "category:未知词类别\r\n" +
            "remark:备注" +
            "[" +
            "]")
    @PostMapping(path = {"/addUnknownWords/{language}","reviewUnknownWords/{language}"})
    @PreAuthorize("hasAnyAuthority('unknown_words')")
    public String batchAddUnknownWords(@RequestBody List<UnknownWord> unknownWords, @PathVariable("language") String language) throws UnSupportedLanguageException {

        UnknownWordService<? extends UnknownWord> unknownWordService = taggingServiceFactory.getUnknownWordService(language);
        if (unknownWords.size() > 0) {
            TaggingService taggingService = taggingServiceFactory.getTaggingService(language);
            taggingService.updateUpdateByAndUnknownWord(unknownWords.get(0).getTagId());
        }
        for (UnknownWord unknownWord : unknownWords) {
            if (unknownWord.getId() != null && unknownWord.getId() != -1) {
                unknownWordService.update(unknownWord);
            } else {
                unknownWordService.add(unknownWord);
            }
        }
        userService.incrementComplete(language);
        return ResponseUtils.build(HttpStatus.OK.value(), "add unknownWords success!");
    }

//    @PostMapping("/reviewUnknownWords/{language}")
//    @ApiOperation(value = "修改多个未知词", notes = "所需权限(unknown_words)" +
//            "restful的参数->language->malay/indonesian/philippines\r\n" +
//            "id:未知词唯一id\r\n" +
//            "tagId:父标签id\r\n" +
//            "unknownWordCorrect:未知词纠正\r\n" +
//            "category:未知词类别\r\n" +
//            "remark:备注\r\n" +
//            "修改[{\n" +
//            "  \"id\": 34176,\n" +
//            "  \"unknownWordCorrect\": \"liyuan1\",\n" +
//            "  \"category\": 未知词的所属类别1,\n" +
//            "  \"remark\": \"就是一个人名1\"\n" +
//            "},{" +
//            "\"id\":1234," +
//            "  \"unknownWordCorrect\": \"liyuan2\",\n" +
//            "  \"category\": 未知词的所属类别2,\n" +
//            "  \"remark\": \"就是一个人名2\"\n" +
//            "}]")
//    @PreAuthorize("hasAnyAuthority('unknown_words')")
//    public String reviewUnknownWords(@RequestBody List<UnknownWord> unknownWords, @PathVariable("language") String language) throws UnSupportedLanguageException {
//        UnknownWordService<? extends UnknownWord> unknownWordService = taggingServiceFactory.getUnknownWordService(language);
//        if (unknownWords.size() > 0) {
//            TaggingService taggingService = taggingServiceFactory.getTaggingService(language);
//            UnknownWord unknownWord = unknownWordService.queryById(unknownWords.get(0).getId());
//            taggingService.updateUpdateByAndUnknownWord(unknownWord.getTagId());
//        }
//        for (UnknownWord unknownWord : unknownWords) {
//            unknownWordService.update(unknownWord);
//        }
//        userService.incrementComplete(language);
//        return ResponseUtils.build(HttpStatus.OK.value(), "update unknownWords success!");
//    }
}
